/*!
 * \file te_trans.c
 *
 * \brief 交易通信
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.
 *
 * \version 1.0
 * \author songbb
 * \date 2016/09/24
 *
 */

#include "conntrack.h"
#include "frct_comm.h"
#include "frreport_comm.h"

#include "te_core.h"
#include "te_comm.h"
#include "te_trans.h"


#define TE_STMT_TIMEOUT   5 * 60   //单位秒
struct timeval g_st_time;

/*******************************************************************************
*  FUNC     :  检查是否超时
*  ARGS     :  p_node           当前节点
*           :  p_data
*  RTN      :  1   (成功)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __ct_check_timeout(Frlist_node* p_node, const void *p_data)
{
    L7_te_stmt *p_st_stmt = NULL;
    Frhash_header *p_hash_stmt = (Frhash_header *)p_data;

    p_st_stmt = (L7_te_stmt *)p_node->data;

    if (p_st_stmt->st_req_end_timestamp.tv_sec + TE_STMT_TIMEOUT <= g_st_time.tv_sec)
    {
        frhash2_del(p_hash_stmt, p_node, te_stmt_node_free);
        return 1;
    }

    return 1;
}

/*******************************************************************************
*  FUNC     :  清除hash中超时的node
*  ARGS     :  p_st_sess                            (L7session_te_private)
*  ARGS     :  p_hash_stmt                          (hash)
*  ARGS     :  st_timestamp                         (当前时间)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __te_clear_timeout_stmt(L7session_te_private *p_st_sess
                                        , Frhash_header *p_hash_stmt
                                        , struct timeval st_timestamp)
{
    if (p_st_sess->st_timestamp.tv_sec == 0)
    {
        p_st_sess->st_timestamp = st_timestamp;
        return;
    }
    else if (p_st_sess->st_timestamp.tv_sec + TE_STMT_TIMEOUT > st_timestamp.tv_sec)
        return;
    else
        p_st_sess->st_timestamp = st_timestamp;

    g_st_time = st_timestamp;
    frhash2_run(p_hash_stmt, p_hash_stmt, __ct_check_timeout);

    return;
}

int te_sync_async_req(Conntrack *p_st_conn
                    , L7_te_packet *p_st_te_packet
                    , Frhash_header *p_st_hash_report)
{
    TE_PRINT_INFO("te_sync_async_req...\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_te_private *p_st_session_private = (L7session_te_private *) frct_get_session_private(p_st_session);
    Frhash_header *p_hash_stmt = p_st_session_private->p_hash_stmt;
    Frreport_body_data *p_st_body = NULL;
    L7_te_stmt *p_st_stmt = NULL;
    Frlist_node *p_st_node = NULL;
    char *p_key_data = NULL;
    char *p_user_data = NULL;
    char *p_filename = NULL;
    char *p_title = NULL;

    if (bytebuff_skip(p_st_te_packet->p_st_packet, p_st_te_packet->st_te_header.ui_header_len) != FR_SUCC)
        goto error;

    if (p_st_te_packet->st_te_header.i_key_data_len > 0)
    {
        if ((p_key_data = (char *) frmalloc(p_st_te_packet->st_te_header.i_key_data_len * sizeof(char))) == NULL)
        {
            TE_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes(p_st_te_packet->p_st_packet, p_key_data, (unsigned int) p_st_te_packet->st_te_header.i_key_data_len) != FR_SUCC)
            goto error;
    }

    if (p_st_te_packet->st_te_header.i_user_data_len > 0)
    {
        if ((p_user_data = (char *) frmalloc(p_st_te_packet->st_te_header.i_user_data_len * sizeof(char))) == NULL)
        {
            TE_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes(p_st_te_packet->p_st_packet, p_user_data, (unsigned int) p_st_te_packet->st_te_header.i_user_data_len) != FR_SUCC)
            goto error;
#if APM_TE_DBG
        char *p_user_data2 = NULL;
        if ((p_user_data2 = (char *) frmalloc((p_st_te_packet->st_te_header.i_user_data_len + 1) * sizeof(char))) == NULL)
        {
            TE_MALLOCK_ERR;
            goto error;
        }
        memcpy(p_user_data2, p_user_data, p_st_te_packet->st_te_header.i_user_data_len);
        p_user_data2[p_st_te_packet->st_te_header.i_user_data_len] = '\0';
        TE_PRINT_WARN("UserData:[%s]\n", p_user_data2);
        te_free((void **) &p_user_data2);
#endif
    }

    if (p_st_te_packet->st_te_header.i_filename_len > 0)
    {
        if ((p_filename = (char *) frmalloc((p_st_te_packet->st_te_header.i_filename_len + 1) * sizeof(char))) == NULL)
        {
            TE_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes(p_st_te_packet->p_st_packet, p_filename, (unsigned int) p_st_te_packet->st_te_header.i_filename_len) != FR_SUCC)
            goto error;
        p_filename[p_st_te_packet->st_te_header.i_filename_len] = '\0';
    }

    // 新建上报数据结构体
    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;

    // 服务名
    if (p_st_te_packet->st_te_header.arr_svcname[0] != '\0')
    {
        if (frreport_body_l7_add_str(p_st_body, APM_DTS_REPORT_REQ_SERVICE_NAME, p_st_te_packet->st_te_header.arr_svcname) != FR_SUCC)
            goto error;
        if (frreport_body_l7_add_str(p_st_body, APM_DTS_REPORT_REQ_SERVICE_METHOD, "call") != FR_SUCC)
            goto error;
        if ((p_title = (char *) frmalloc((strlen(p_st_te_packet->st_te_header.arr_svcname) + strlen("call ") + 1) * sizeof(char))) == NULL)
        {
            TE_MALLOCK_ERR;
            goto error;
        }
        snprintf(p_title, strlen(p_st_te_packet->st_te_header.arr_svcname) + strlen("call ") + 1, "call %s", p_st_te_packet->st_te_header.arr_svcname);
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, p_title) != FR_SUCC)
            goto error;
        te_free((void **) &p_title);
    }
    else
    {
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, "Unknown Service") != FR_SUCC)
            goto error;
        if (frreport_body_l7_add_str(p_st_body, APM_DTS_REPORT_REQ_SERVICE_NAME, "Unknown Service") != FR_SUCC)
            goto error;
    }
    // 数据包类型
    if (frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_REQ_PACKET_TYPE, TE_PKT_TYPE2STR(p_st_te_packet->st_te_header.pkt_type)) != FR_SUCC)
        goto error;
    // 发起节点名
    if (frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_REQ_ORIGINAL_NODE, p_st_te_packet->st_te_header.arr_original_node) != FR_SUCC)
        goto error;
    // 发送节点名
    if (frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_REQ_SEND_NODE, p_st_te_packet->st_te_header.arr_send_node) != FR_SUCC)
        goto error;
    // 接收节点名
    if (frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_REQ_RECV_NODE, p_st_te_packet->st_te_header.arr_recv_node) != FR_SUCC)
        goto error;
    // 事务序号
    if (frreport_body_l7_add_int(p_st_body, APM_TE_REPORT_TID, p_st_te_packet->st_te_header.i_tid) != FR_SUCC)
        goto error;
    // 事务分支序号
    if (frreport_body_l7_add_int(p_st_body, APM_TE_REPORT_SUBTID, p_st_te_packet->st_te_header.i_subtid) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_DTS_REPORT_REQ_ARG_SIZE, p_user_data ? 1 : 0) != FR_SUCC)
        goto error;
    // 用户数据
    if (p_user_data && frreport_body_l7_add_bin(p_st_body, APM_DTS_REPORT_REQ_ARG_DATA, p_user_data, (unsigned int) p_st_te_packet->st_te_header.i_user_data_len) != FR_SUCC)
        goto error;
    // 用户关键数据
    if (p_key_data && frreport_body_l7_add_bin(p_st_body, APM_TE_REPORT_REQ_KEY_DATA, p_key_data, (unsigned int) p_st_te_packet->st_te_header.i_key_data_len) != FR_SUCC)
        goto error;
    // 文件名
    if (p_filename && frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_REQ_FILENAME, p_filename) != FR_SUCC)
        goto error;

    if ((p_st_stmt = (L7_te_stmt *) frmalloc(sizeof(L7_te_stmt))) == NULL)
    {
        TE_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_stmt, 0x00, sizeof(L7_te_stmt));

    // 上报数据
    if (te_report_msg_data_req(p_st_conn, p_st_te_packet, p_st_body, p_st_hash_report) != FR_SUCC)
        goto error;

    // 为确保不重复,先删除
    frhash2_delLong(p_hash_stmt, p_st_te_packet->st_te_header.i_tid * 10000 + p_st_te_packet->st_te_header.i_subtid, te_stmt_node_free);

    p_st_stmt->p_report_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_body);
    p_st_stmt->p_report_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_body);
    p_st_stmt->st_req_end_timestamp.tv_sec = p_st_te_packet->st_timestamp_last.tv_sec;
    p_st_stmt->st_req_end_timestamp.tv_usec = p_st_te_packet->st_timestamp_last.tv_usec;

    p_st_node = frlist_node_create(p_st_stmt);
    if (frhash2_addLong(p_hash_stmt, p_st_te_packet->st_te_header.i_tid * 10000 + p_st_te_packet->st_te_header.i_subtid, p_st_node) != FR_SUCC)
        goto error;
    p_st_stmt = NULL;

    __te_clear_timeout_stmt(p_st_session_private, p_hash_stmt, p_st_te_packet->st_timestamp_last);

    te_free((void **) &p_key_data);
    te_free((void **) &p_user_data);
    te_free((void **) &p_filename);
    return FR_SUCC;
error:
    te_free((void **) &p_title);
    te_free_stmt(&p_st_stmt);
    te_stmt_node_free(p_st_node);
    te_free((void **) &p_key_data);
    te_free((void **) &p_user_data);
    te_free((void **) &p_filename);
    frreport_body_free(&p_st_body);
    return FR_FAIL;
}

int te_sync_async_resp(Conntrack *p_st_conn
                    , L7_te_packet *p_st_te_packet
                    , Frhash_header *p_st_hash_report)
{
    TE_PRINT_INFO("te_sync_async_resp...\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_te_private *p_st_session_private = (L7session_te_private *) frct_get_session_private(p_st_session);
    Frhash_header *p_hash_stmt = p_st_session_private->p_hash_stmt;
    Frreport_body_data *p_st_body = NULL;
    L7_te_stmt *p_st_stmt = NULL;
    Frlist_node *p_st_node = NULL;
    char *p_key_data = NULL;
    char *p_user_data = NULL;
    char *p_filename = NULL;

    if (bytebuff_skip(p_st_te_packet->p_st_packet, p_st_te_packet->st_te_header.ui_header_len) != FR_SUCC)
        goto error;

    if (p_st_te_packet->st_te_header.i_key_data_len > 0)
    {
        if ((p_key_data = (char *) frmalloc(p_st_te_packet->st_te_header.i_key_data_len * sizeof(char))) == NULL)
        {
            TE_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes(p_st_te_packet->p_st_packet, p_key_data, (unsigned int) p_st_te_packet->st_te_header.i_key_data_len) != FR_SUCC)
            goto error;
    }

    if (p_st_te_packet->st_te_header.i_user_data_len > 0)
    {
        if ((p_user_data = (char *) frmalloc(p_st_te_packet->st_te_header.i_user_data_len * sizeof(char))) == NULL)
        {
            TE_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes(p_st_te_packet->p_st_packet, p_user_data, (unsigned int) p_st_te_packet->st_te_header.i_user_data_len) != FR_SUCC)
            goto error;
#if APM_TE_DBG
        char *p_user_data2 = NULL;
        if ((p_user_data2 = (char *) frmalloc((p_st_te_packet->st_te_header.i_user_data_len + 1) * sizeof(char))) == NULL)
        {
            TE_MALLOCK_ERR;
            goto error;
        }
        memcpy(p_user_data2, p_user_data, p_st_te_packet->st_te_header.i_user_data_len);
        p_user_data2[p_st_te_packet->st_te_header.i_user_data_len] = '\0';
        TE_PRINT_WARN("UserData:[%s]\n", p_user_data2);
        te_free((void **) &p_user_data2);
#endif
    }

    if (p_st_te_packet->st_te_header.i_filename_len > 0)
    {
        if ((p_filename = (char *) frmalloc((p_st_te_packet->st_te_header.i_filename_len + 1) * sizeof(char))) == NULL)
        {
            TE_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes(p_st_te_packet->p_st_packet, p_filename, (unsigned int) p_st_te_packet->st_te_header.i_filename_len) != FR_SUCC)
            goto error;
        p_filename[p_st_te_packet->st_te_header.i_filename_len] = '\0';
    }

    // 新建上报数据结构体
    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;

    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_RESP_CODE, p_st_te_packet->st_te_header.s_ret_code) != FR_SUCC)
        goto error;
    // 数据包类型
    if (frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_RESP_PACKET_TYPE, TE_PKT_TYPE2STR(p_st_te_packet->st_te_header.pkt_type)) != FR_SUCC)
        goto error;
    // 发起节点名
    if (frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_RESP_ORIGINAL_NODE, p_st_te_packet->st_te_header.arr_original_node) != FR_SUCC)
        goto error;
    // 发送节点名
    if (frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_RESP_SEND_NODE, p_st_te_packet->st_te_header.arr_send_node) != FR_SUCC)
        goto error;
    // 接收节点名
    if (frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_RESP_RECV_NODE, p_st_te_packet->st_te_header.arr_recv_node) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_DTS_REPORT_RESP_ARG_SIZE, p_user_data ? 1 : 0) != FR_SUCC)
        goto error;
    // 用户数据
    if (p_user_data && frreport_body_l7_add_bin(p_st_body, APM_DTS_REPORT_RESP_ARG_DATA, p_user_data, (unsigned int) p_st_te_packet->st_te_header.i_user_data_len) != FR_SUCC)
        goto error;
    // 用户关键数据
    if (p_key_data && frreport_body_l7_add_bin(p_st_body, APM_TE_REPORT_RESP_KEY_DATA, p_key_data, (unsigned int) p_st_te_packet->st_te_header.i_key_data_len) != FR_SUCC)
        goto error;
    // 文件名
    if (p_filename && frreport_body_l7_add_str(p_st_body, APM_TE_REPORT_RESP_FILENAME, p_filename) != FR_SUCC)
        goto error;

    if ((p_st_node = frhash2_getLong(p_hash_stmt, p_st_te_packet->st_te_header.i_tid * 10000 + p_st_te_packet->st_te_header.i_subtid)) == NULL)
        goto error;
    if ((p_st_stmt = (L7_te_stmt *) FRLIST_GET_NODE_DATA(p_st_node)) == NULL)
        goto error;

    // 上报数据
    if (te_report_msg_data_resp(p_st_conn, p_st_te_packet, p_st_stmt, p_st_body, p_st_hash_report) != FR_SUCC)
        goto error;

    frhash2_delLong(p_hash_stmt, p_st_te_packet->st_te_header.i_tid * 10000 + p_st_te_packet->st_te_header.i_subtid, te_stmt_node_free);
    te_free((void **) &p_key_data);
    te_free((void **) &p_user_data);
    te_free((void **) &p_filename);
    return FR_SUCC;
error:
    frhash2_delLong(p_hash_stmt, p_st_te_packet->st_te_header.i_tid * 10000 + p_st_te_packet->st_te_header.i_subtid, te_stmt_node_free);
    te_free((void **) &p_key_data);
    te_free((void **) &p_user_data);
    te_free((void **) &p_filename);
    frreport_body_free(&p_st_body);
    return FR_FAIL;
}
